######################################################################
# File: game/models.py                             Part of DjangoMUD #
#                                                                    #
# Copyright (C) 2010, Joachim Pileborg.                              #
# All rights reserved.                                               #
#                                                                    #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions #
# are met:                                                           #
#                                                                    #
#   o Redistributions of source code must retain the above copyright #
#     notice, this list of conditions and the following disclaimer.  #
#   o Redistributions in binary form must reproduce the above        #
#     copyright notice, this list of conditions and the following    #
#     disclaimer in the documentation and/or other materials         #
#     provided with the distribution.                                #
#   o Neither the name of the author nor the names of DjangoMUDs     #
#     contributors may be used to endorse or promote products        #
#     derived from this software without specific prior written      #
#     permission.                                                    #
#                                                                    #
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             #
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,        #
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           #
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           #
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS  #
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,#
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,           #
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR #
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY       #
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     #
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF #
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF    #
# SUCH DAMAGE.                                                       #
######################################################################

from django.db import models
from django.contrib.auth.models import User
from django.db.models import signals as model_signals

######################################################################

class BaseObject(models.Model):
    """
    This is the base class for all other tangible objects in the game.
    """
    name = models.CharField(max_length=40, editable=False)           # Name of the object
    alias = models.CharField(max_length=160, null=True, blank=True)  # Aliases of the object
    plural = models.CharField(max_length=160, null=True, blank=True) # Plural names of the object
    short = models.CharField(max_length=80, null=True, blank=True)   # Short (one line) description of the object
    description = models.TextField(null=True, blank=True)            # Long description of the object

    # For monsters, items and locations, the description field is passed through the template engine

    def __unicode__(self):
        return u'%s#%d' % (self.name, self.id or -1)

    class Meta:
        abstract = True  # Mark this as a Django abstract class

######################################################################

class Location(BaseObject):
    pass

class Exit(BaseObject):
    leading_from = models.ForeignKey(Location, related_name='exits')
    leading_to = models.ForeignKey(Location)

######################################################################

# This model can't be abstract because it is referenced from other models.
class Character(BaseObject):
    level = models.PositiveIntegerField(default=0)

class Monster(Character):
    location = models.ForeignKey(Location, related_name='monsters', null=True, blank=True)

class Player(Character):
    user = models.ForeignKey(User, unique = True)   # Link to a Django user
    location = models.ForeignKey(Location, related_name='players', null=True, blank=True)
    homepage = models.URLField(null=True, blank=True)
    last_login_from = models.IPAddressField(editable=False)
    login_tries = models.PositiveIntegerField(default=0, editable=False)
    prompt = models.CharField(max_length=40, null=True, blank=True)

    # Make the name into a property, to make sure the players name and the
    # users name always are synched.
    @property
    def name(self):
        return self.user.username
    @name.setter
    def name(self, newname):
        if newname is not None and len(newname) > 0:
            try:
                self.user.username = newname
                self.user.save()
            except AttributeError:
                # Model is just being loaded
                pass
        else:
            raise ValueError('Not a legal name')

    connection = None  # Link to the network connection object

def _user_create_player(sender, **kw):
    """Called when a user is created, to create the player for that user."""
    created = kw.get('created', False)
    if created:
        user = kw.get('instance', None)
        if user is not None:
            import datetime

            profile = Player(name=user.username, user=user,
                             last_login_from='0.0.0.0')
            profile.save()

model_signals.post_save.connect(_user_create_player, sender=User)

######################################################################

class Item(BaseObject):
    character = models.ForeignKey(Character, related_name='inventory', null=True, blank=True)
    location  = models.ForeignKey(Location , related_name='items'    , null=True, blank=True)

######################################################################

# TODO: Other models needed?
# TODO: Shops?
# TODO: Triggers? Stored here, or in other modules? Or maybe in another Django app?
#       Also, should it be simple pre-defined triggers, or programmable?
#       If programmable, what language? Create my own, or use Python?

######################################################################
